#!/usr/bin/env python3
# Created by han on 2016/5/30
import os,pickle,getpass,json,shutil

USER_INFO = 'user_info.db'
USER_INFO_BAK = 'user_info.db.bak'
SEARCH_FILE = 'search.txt'
SEARCH_FILE_BAK = 'search.txt.bak'


def  register_info_outer(func):
    """
    用户注册装饰器函数：
    :param func: 装饰器内层函数，对register函数进行功能的增加，增加完善用户信息的功能。
    :return: 返回内层函数（给register增加功能的函数体自身）
    """
    def all_info():
        r = func()
        while True:
            perfect_info = input("是否完善您的信息【y】填写完整信息，【n】暂不完善： ")
            if perfect_info == "n":
                return r
            elif perfect_info == "y":
                while True:
                    addr = input("请输入您的家庭地址： ")
                    tel = input("请输入您的联系电话： ")
                    email = input("请输入您的邮箱地址： ")
                    if addr and tel.isdigit() and email:
                        r["addr"] = addr
                        r['tel'] = tel
                        r['email'] = email
                        return r
                    else:
                        print("输入有误请，重新输入")
            else:
                continue
    return all_info


@register_info_outer
def register_info():
    """
    接受用户注册信息
    :return: 字典形式返回用户注册信息
    """
    while True:
        auth = input("请选择 1.注册管理员账号，2.注册普通账号: ")
        if auth.isdigit() and 0 < int(auth) < 3:
            #如果选择是数字并且在范围内
            user_name = input("请输入您的用户名： ")
            user_pass = input("请输入您的密码: ")
            # if user_name.isalnum() and user_pass.isdigit() :
            if user_name.isalnum() and user_pass:
                #如果用户名是字符且密码有内容
                # user_pass = int(user_pass)
                if not os.path.exists(USER_INFO):                   #如果用户文件不存在
                    return {"user": user_name, "passwd": user_pass, "auth": auth,"addr":"","email":"","tel":""} #直接返回要注册用户字典
                with open(USER_INFO, "r+", encoding="utf-8") as userr_file:             #存在用户文件则打开这个文件
                    for line in userr_file:                                             #每一行循环遍历
                        user_dict = json.loads(line)                                    #将这行使用json序列化变回字典
                        if user_dict["user"] == user_name:
                            print("【%s】用户已经存在" % user_dict["user"])      #如果这个字典user字段和用户输的一样，则提示存在
                            break
                        else:
                            return {"user": user_name, "passwd": user_pass, "auth": auth, "addr": "", "email": "","tel": ""}                                                                            # 入一样则提示用户

            else:
                print("输入有误，请您重新输入： ")
                continue
        else:
            print("输入有误，请您重新输入： ")





def register(**kwargs):
    """
    接收用户信息并将信息存入文件
    :param kwargs: 用户注册信息的字典
    :return: 存入成功则返回True
    """
    d = {"user": "", "passwd": "", "addr": "", "is_login": 0, "is_lock": 3, "tel": "", "auth": "", "email": ""}   #初始化用户信息字典
    h = kwargs                                              #用户注册信息传入的字典
    if not os.path.exists(USER_INFO):
        #如果没有用户信息文件
        d["user"] = h["user"]
        d["passwd"] = h["passwd"]
        d["auth"] = h["auth"]
        d["email"] = h["email"]
        d["tel"] = h["tel"]
        d["addr"] = h["addr"]
        print(h["auth"],'+++++++++++++')
        if h["auth"] == '1':          #对用户信息中的管理位进行标注 1为管理员，2位普通用户
            auth_user = "管理员"
        else:
            auth_user = "普通用户"
        user_str = "{user}\t{email}\t{tel}\t{addr}\t{auth}\n".format(user=h["user"],email=h["email"],
                                                                   tel=h["tel"],addr=h["addr"],auth=auth_user)
        with open(USER_INFO, "w",encoding="utf-8") as userw_file:   #使用json序列dict为str
            in_str = json.dumps(d, ensure_ascii=False) + '\n'       #一个用户一行信息
            userw_file.write(in_str)                                #将序列化后的str存入文件
        with open(SEARCH_FILE,'w',encoding="utf-8") as search_file:
            search_file.write(user_str)
        print("【%s】：【%s】注册成功\n" % (auth_user, h["user"]))
        return True                     #没有文件存放文件后返回值，并且推出当前循环
    #有文件
    d["user"] = h["user"]
    d["passwd"] = h["passwd"]
    d["auth"] = h["auth"]
    d["email"] = h["email"]
    d["tel"] = h["tel"]
    d["addr"] = h["addr"]
    if h["auth"] == '1':
        auth_user = "管理员"
    else:
        auth_user = "普通用户"
    user_str = "{user}\t{email}\t{tel}\t{addr}\t{auth}\n".format(user=h["user"], email=h["email"],
                                                               tel=h["tel"], addr=h["addr"], auth=auth_user)
                                                                #格式化搜索文件的字符串
    with open(USER_INFO,'a',encoding="utf-8") as usera_file:
        in_str = json.dumps(d,ensure_ascii=False) + "\n"                #将字典存入字典文件中
        usera_file.write(in_str)
    with open(SEARCH_FILE, 'a', encoding="utf-8") as search_file:       #将搜索字符串存入搜索文件中
        search_file.write(user_str)
    print("【%s】：【%s】注册成功\n"%(auth_user,h["user"]))
    return True                     #有文件返回True，并退出当前循环


def modifi_outer(func):
    """
    管理界面的装饰器，如果是管理员则返回原函数，否则就执行普通用户的管理界面
    :param func: modify_msg原函数
    :return: 内层inner函数
    """
    def inner(**kwargs):
        info = kwargs
        print(info)
        if info["auth"] == '1':
            return func()
        else:
            other_user(info['user'])
    return inner


def login_info(user,passwd):
    """
    接收用户的输入的用户名，密码，并返回当前登陆用户的信息。
    :param user: 用户输入的用户名
    :param passwd: 用户输入的密码
    :return: 返回当登陆用户的user
    """
    while True:
        user_name = []
        with open(USER_INFO,"r",encoding="utf-8") as userr_file:   #读取用户信息文件
            for u in userr_file:                                    #循环用户信息文件
                dict_u = json.loads(u)
                user_name.append((dict_u["user"],(dict_u["passwd"])))        #把所有的用户名密码做成元组添加到user_name的列表中
            # if (user,int(passwd)) not in user_name:                           #将用户输入的用户名密码组成元组，和列表中元素比对，不在就是用户名密码有错误
            if (user,passwd) not in user_name:                           #将用户输入的用户名密码组成元组，和列表中元素比对，不在就是用户名密码有错误
                print("用户名或密码有误，请重新输入\n")
                return False
        with open(USER_INFO, "r", encoding="utf-8") as userr_auth:          #在就再打开这个文件获取对应用户的信息
                for p in userr_auth:
                    dict_p = json.loads(p)                                  #序列化一条信息
                    if user == dict_p["user"]:                              #如果用户名和当前行的user匹配就返回这一整条的信息
                        return dict_p
                    else:
                        continue


@modifi_outer
def modify_msg(**kwargs):
    """
    管理员的管理目录
    :param kwargs:传入的登陆者自身的信息字典
    :return: 返回搜索成功与否
    """
    while True:
        self_info = kwargs   #这个参数在装饰器里面用到了
        user_chose = input("1、修改用户信息  2、搜索全部用户信息 【或任意键返回】： ")
        if user_chose == "1":
            return 1
        elif user_chose == '2':
            return 2
        else:
            return False


def search_info():
    """
    返回需要搜索的内容
    :return:  搜索的内容
    """
    while True:
        search_inp = input("请输入您要搜索的内容或按【回车】返回： ")
        if search_inp:
            return search_inp
        else:
            break


def search(arg):
    """
    管理员搜索功能，并打印搜索结果
    :param arg: 想要搜索的内容
    :return: 搜索是否成功
    """
    search_list = []
    search_num = 0
    while True:
        with open(SEARCH_FILE,'r',encoding="utf-8") as sear_file:
            for sear_line in sear_file.readlines():
               if sear_line.count(arg) > 0:
                   search_list.append(sear_line.replace(arg,"\033[33;35m%s\033[0m"%arg))       #将匹配的行插入到空列表中，将搜索到的内容做个替换，替换成彩色的
                   search_num += sear_line.count(arg)             #把每一行的搜索出来的数字都累计加起来
        if search_num > 0:
        #如果有值就代表搜索到了数据
            search_msg = ("共找到: \033[33;35m%s\033[0m 条信息" % search_num).center(20,'-')
            print(search_msg)
            for i in search_list:
                print(i)
            return True
        else:
            print("\033[33;35m 没有您所找的信息 \033[0m")
            return False


def other_user(arg):
    """
    普通用户主菜单
    :param arg: 登陆用户名
    :return:
    """
    while True:
        user_chose = input("1、修改信息  2、查看信息  【或任意键返回】： ")
        if user_chose == "1":
            #print(arg)
            new_sea = other_modify(arg)
            if new_sea and os.path.exists(SEARCH_FILE_BAK) and os.path.exists(USER_INFO_BAK) :
                print("1、保存修改内容 2、放弃修改内容")
                user_sure = input("你是否确定保存修改的内容： ")
                if user_sure == "1":                                #确定修改
                    mv_ok =  file_process()                         #将bak文件改名为原文件，把原文件删除
                    if mv_ok:
                        print("您修改的信息已经保存成功")
                    else:
                        print("修改保存失败，请重试")
                        continue
                else:                                           #放弃修改则返回重新修改界面
                    continue
        elif user_chose == "2":
            check_user_info(arg)
        else:
            break


def check_user_info(user_name):
    with open(SEARCH_FILE,'r',encoding="utf-8") as sear_file:
        for i in sear_file:
            if i.startswith(user_name):
                print(i)
                return True






def other_modify(arg):
    """
    普通用户修改个人信息
    :param arg: 登陆的用户名
    :return: 修改成功后返回真
    """
    with open(USER_INFO,'r') as userr_file,open(USER_INFO_BAK,'w') as userw_bak:        #同时以读和写模式打开两个备份文件用户信息文件
        while True:
            user = input("用户名： ")
            passwd = input("密码： ")
            t = [user,passwd]                                               #判断用户输入的用户名和密码是否为真，用户输入的用户名和密码不能为空
            if not all(t):                                                  #如果为空重新输入
                print("输入有误请重新输入： ")
                continue
            break
        for i in userr_file:                                                #循环原用户信息的文件
            #print(i)
            if json.loads(i)["user"] == arg:                                #先用json还原字典属性，找到user字段，并判断如果和用户名相同
                # flag = False
                addr = input("请输入家庭住址： ")                             #收集新的用户输入的信息
                email = input("请输入邮箱地址： ")
                tel = input("请输入您的电话： ")
                auth = json.loads(i)['auth']                                #获取到原用户登陆的属性
                new_user = {"user":user,"passwd":passwd,"addr":addr,"email":email,"tel":tel,"is_lock":3,"auth":auth} #创建新的用户信息字典
                json_user = json.dumps(new_user,ensure_ascii=False ) + '\n'                     #json序列化为字符串
                userw_bak.write(json_user)                                                      #存放到文件中
                continue
            userw_bak.write(i)                                              #如果没有匹配到相同名字的则拷贝到bak文件中

        with open (SEARCH_FILE,'r',encoding="utf-8") as sear_file,open(SEARCH_FILE_BAK,'w',encoding="utf-8") as seaw_file:
        #以读和写模式打开搜索文件
            if auth == '1':
                auth_flag = "管理员"
            elif auth == '2':
                auth_flag = "普通用户"
            for i in sear_file:                             #循环原搜索文件
                if i.startswith(arg) :                      #如果开头是和用户登陆的用户名匹配
                    new = "{user}\t{email}\t{tel}\t{addr}\t{auth}\n".format(user=user, email=email, tel=tel, addr=addr, auth=auth_flag)
                    #格式化用户信息的搜索字符串
                    seaw_file.write(new)                    #写到搜索文件中
                    continue
                seaw_file.write(i)                                 #没有匹配到则直接拷贝过去。
        return True                                         #返回为真


def file_process():
    """
    处理用户信息文件和搜索文件
    :return: 操作完后返回为真
    """
    os.remove(SEARCH_FILE)                              #删除原用户信息文件
    shutil.move(SEARCH_FILE_BAK,SEARCH_FILE)            #移动bak文件并改名为原文件名称
    os.remove(USER_INFO)                                #删除原搜索文件
    shutil.move(USER_INFO_BAK,USER_INFO)                #移动bak文件并改名为原文件
    return True


def input_auth(*args):
    while True:
        menu = []
        for i in args:
            menu.append(i)
        for a in enumerate(menu):
            print(a[0]+1,a[1])
        user_chose = input("请输入您的选择：")
        if user_chose.isdigit() :
            user_chose = int(user_chose)
            if user_chose <= len(menu):
                return user_chose
            else:
                break
        # elif user_chose == "b":
        #     break
        else:
            print("\n您输入有误，请重新输入")

# r = register_info()
# print(r)


# a = search('adfafd')
#modify_msg()